#include "TokenBlock.hpp"
#include "symbol.hpp"
#include "util.hpp"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 保留字映射表
static const struct {
  const char *keyword;
  SymbolType sym;
} reserved_map[] = {
#define SYMBOL(a, b, c) {c, a},
    SYMBOL_LIST
#undef SYMBOL
};

struct TokenBlock *malloc_TokenBlock(int char_len) {
  struct TokenBlock *res =
      (struct TokenBlock *)malloc(sizeof(struct TokenBlock));
  res->token = (char *)malloc((char_len + 1) * sizeof(char));
  res->nextBlock = nullptr;
  return res;
}

void free_TokenBlock(struct TokenBlock *ptr) {
  free(ptr->token);
  free(ptr);
}

void free_TokenList(struct TokenBlock *current) {
  // 释放TokenBlock链表内存
  struct TokenBlock *next;
  while (current != nullptr) {
    next = current->nextBlock;
    free_TokenBlock(current);
    current = next;
  }
}

// 识别symbol的类型
SymbolType determine_symbol_type(const char *token) {
  // 临时缓冲区用于大小写不敏感比较
  char lower_token[MAX_TOKEN_LEN];
  strncpy(lower_token, token, MAX_TOKEN_LEN);
  lower_token[MAX_TOKEN_LEN - 1] = '\0';

  // 转换为小写（保留字不敏感）
  for (int i = 0; lower_token[i]; i++) {
    lower_token[i] = tolower(lower_token[i]);
  }

  // 匹配保留字和标点符号
  for (size_t i = 0; i < sizeof(reserved_map) / sizeof(reserved_map[0]); i++) {
    if (strcmp(lower_token, reserved_map[i].keyword) == 0) {
      return reserved_map[i].sym;
    }
  }
  // 数字类型
  if (is_all_digits(token)) {
    return NUMBER_SYM;
  }
  // 标识符
  if (is_valid_ident(token)) {
    return IDENT_SYM;
  }

  // 未知token
  return UNKNOWN_SYM;
}

// 遍历链表，确定每个token的符号类型
void type_token_list(struct TokenBlock *head) {
  struct TokenBlock *current = head;
  while (current != nullptr) {
    current->sym = determine_symbol_type(current->token);
    current = current->nextBlock;
  }
}

static CharType get_char_type(unsigned char ch) {
  if (ch > 128) {
    return ILLEGAL;
  } else if (ch <= 32) {
    return BLANK;
  } else if ((ch >= 48 && ch <= 57) || (ch >= 65 && ch <= 90) ||
             (ch >= 97 && ch <= 122)) {
    return NUMBER_LETTER;
  } else {
    return PUNCTUATION;
  }
}

struct TokenBlock *append_token(struct TokenBlock *tail_ptr, const char buf[]) {
  tail_ptr->nextBlock = malloc_TokenBlock(strlen(buf));
  tail_ptr = tail_ptr->nextBlock;
  strcpy(tail_ptr->token, buf);
  return tail_ptr;
}

struct TokenBlock *tokens_appender(struct TokenBlock *tail_ptr, char buf[]) {
  int length = strlen(buf);
  char *last_token = buf;
  for (int i = 0; i < length; ++i) {
    if (buf[i] == ';' || buf[i] == '(' || buf[i] == ')') {
      char single_punctuation[2] = {buf[i], 0};
      buf[i] = 0;
      if (last_token < buf + i) {
        tail_ptr = append_token(tail_ptr, last_token);
      }
      tail_ptr = append_token(tail_ptr, single_punctuation);
      last_token = buf + i + 1;
    }
  }
  if (last_token < buf + length) {
    tail_ptr = append_token(tail_ptr, last_token);
  }
  return tail_ptr;
}

// 假设没有注释，已经预处理好了，没有语法错误
// 返回token的链表，没有head
struct TokenBlock *get_tokens(FILE *fp) {
  CharType current_type;
  char buf[MAX_TOKEN_LEN], buf_char;
  int current_char_idx = 1;

  struct TokenBlock head, *tail_ptr = &head;
  head.nextBlock = nullptr;

  while ((buf_char = fgetc(fp)) != EOF) {
    if ((current_type = get_char_type(buf_char)) == BLANK) {
      continue;
    }

    buf[0] = buf_char;

    while ((buf_char = fgetc(fp)) != EOF &&
           get_char_type(buf_char) == current_type) {
      buf[current_char_idx++] = buf_char;
    }
    buf[current_char_idx] = 0;

    tail_ptr = tokens_appender(tail_ptr, buf);

    if (buf_char == EOF) {
      break;
    } else if (get_char_type(buf_char) != BLANK) {
      fseek(fp, -1, SEEK_CUR);
    }
    current_char_idx = 1;
  }

  return head.nextBlock;
}

struct TokenBlock *get_typed_tokens(FILE *fp) {
  struct TokenBlock *res = get_tokens(fp);
  type_token_list(res);
  return res;
}
